// windowfactory.h : contains a class to create, destroy and manage windows of a certain class
//$Id: WindowFactory.h 42 2009-09-09 03:25:33Z brwarner2 $

#pragma once

//Information structure
struct WindowInfo
{
	//Size
	int width, height;

	//Classname
	std::string classname;
	
	//Window name
	std::string windowName;

	//Menu name
	DWORD dwMenu;
};

//Editor window base class
template<typename T>
class CWindowFactory
{
public:
	//Registers the window class
	bool Register( void )
	{
		//Get the window information
		myInfo.width = myInfo.height = CW_USEDEFAULT;
		myInfo.dwMenu = 0;
		myInfo.windowName = "Editor Window";
		T::WindowInfo(myInfo);

		//Register classes
		T::RegisterClasses();

		//Create the window class
		WNDCLASSEX wc;
		SecureZeroMemory(&wc, sizeof(wc));

		//Setup basic values
		wc.cbSize = sizeof(wc);
		wc.hbrBackground = (HBRUSH)(COLOR_BACKGROUND);
		wc.hIcon = wc.hIconSm = LoadIcon(0, IDI_APPLICATION);
		wc.hCursor = LoadCursor(0, IDC_ARROW);
		wc.hInstance = GetModuleHandle(0);
		wc.lpfnWndProc = Message;
		wc.lpszClassName = myInfo.classname.c_str();
		wc.lpszMenuName = MAKEINTRESOURCE(myInfo.dwMenu);

		//Register
		HRESULT hr = RegisterClassEx(&wc);
		if(SUCCEEDED(hr))
		{
			m_bRegistered = true;
			return true;
		}
		else return false;
	}

	//Creates an instance of a window
	T* Create( int x = CW_USEDEFAULT, int y = CW_USEDEFAULT )
	{
		//Create a new T object
		T* pWindow = new T();

		//Create the window object
		HWND hWnd = CreateWindowEx( WS_EX_CLIENTEDGE, myInfo.classname.c_str(), 
			myInfo.windowName.c_str(), WS_OVERLAPPEDWINDOW, x, y, myInfo.width, myInfo.height, 
			GetDesktopWindow(), 0, GetModuleHandle(0), pWindow );
		ShowWindow(hWnd, SW_SHOW);
		UpdateWindow(hWnd);

		//Return the new instance
		return pWindow;
	}

	//Gets if registered
	bool IsRegistered(void) { return m_bRegistered; }
private:
	//Registered
	bool m_bRegistered;

	//Window information
	WindowInfo myInfo;

	//Static message procedure
	static LRESULT CALLBACK Message( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
	{
		//Check for creation
		if( msg == WM_NCCREATE )
		{
			//Get the create struct
			LPCREATESTRUCT pStruct = reinterpret_cast<LPCREATESTRUCT>(lParam);
			T* pWindow = reinterpret_cast<T*>(pStruct->lpCreateParams);

			//Set its window parameter
			pWindow->SetHWND( hWnd );

			//Save the class into the window information
			SetWindowLongPtr( hWnd, GWLP_USERDATA, reinterpret_cast<LONG>(pWindow) );
		}

		//Get the window class
		T* pWindow = reinterpret_cast<T*>(GetWindowLongPtr( hWnd, GWLP_USERDATA ));
		if( !pWindow ) return DefWindowProc( hWnd, msg, wParam, lParam );

		if( msg == WM_DESTROY )
		{
			LRESULT ret = pWindow->Message( msg, wParam, lParam );
			delete pWindow;
			pWindow = 0;
			SetWindowLongPtr( hWnd, GWLP_USERDATA, 0 );
			DestroyWindow(hWnd);
			return ret;
		}
		else
			//Return their message procedure
			return pWindow->Message( msg, wParam, lParam );
	}
};

//Gets a factory
template<typename T>
CWindowFactory<T>* GetFactory(void)
{
	static CWindowFactory<T> factory;
	if(!factory.IsRegistered()) factory.Register();
	return &factory;
}